﻿using RealTimeCharts.LineChart.common;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Security.RightsManagement;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace RealTimeCharts.LineChart
{
    /// <summary>
    /// 坐标轴，辅助线
    /// </summary>
    public class AxisScaleWindow : AxisWindow
    {
        public AxisScaleProperty scaleX;
        public AxisScaleProperty scaleY;

        public int scalePos;
        public Graphics gs;
        public Color backGround;

        public Rect myRect; //这个Scale包括title的矩形
        public Padding padding;//整个scale的padding
        public Padding windowPadding;//数据窗口的padding

        public Pen borderPen;

        //参考线
        public List<ReferenceLine> referenceLines;

        public AxisScaleWindow()
        {
            dataWnd = new DataWnd();
            windowRect = new Rect(0, 0, 0, 0);
            padding = new Padding(2, 2, 2, 2);
            windowPadding = new Padding(2, 2, 2, 2);
            borderPen = new Pen(new SolidBrush(Color.Black), 1);
            scalePos = (int)(Position.Left | Position.Right | Position.Bottom);
            scaleX = new AxisScaleProperty();
            scaleY = new AxisScaleProperty();
            scaleY.lineProperty.type = LineType.Dashed;
            referenceLines = new List<ReferenceLine>();

            backGround = Color.Beige;
        }

        public AxisScaleWindow(AxisScaleProperty propX, AxisScaleProperty propY, Graphics g, Rect r, int pos, Pen borderPen)
            : this()
        {
            this.scaleX = propX.Clone();
            this.scaleY = propY.Clone();
            this.borderPen = borderPen;
            gs = g;
            this.scalePos = pos;
            this.myRect = new Rect(r.TopLeft, r.BottomRight);
        }

        private Rect GetRemainRect()
        {
            Rect tmpRect = GetRemainRect(this.gs, this.myRect);
            return tmpRect;
        }

        public Rect GetRemainRect(Graphics g, Rect r)
        {
            // 固定设置,最长不能超过9个字符（####.####）
            SizeF scaleTextSizeX = g.MeasureString("9999.9999", scaleX.scaleTextFont);
            SizeF scaleTextSizeY = g.MeasureString("9999.9999", scaleY.scaleTextFont);

            Rect tmpRect = new Rect(r.TopLeft, r.BottomRight);
            tmpRect.X += (padding.left + windowPadding.left);
            tmpRect.Y += (padding.top + windowPadding.top);
            tmpRect.Width -= (padding.left + windowPadding.left + padding.right + windowPadding.right);
            tmpRect.Height -= (padding.top + windowPadding.top + padding.bottom + windowPadding.bottom);

            if ((scalePos & (int)Position.Left) != 0)
            {
                tmpRect.X += (scaleTextSizeY.Width);
                tmpRect.Width -= (scaleTextSizeY.Width);
            }

            if ((scalePos & (int)Position.Right) != 0)
            {
                tmpRect.Width -= (scaleTextSizeY.Width);
            }

            if ((scalePos & (int)Position.Top) != 0)
            {
                tmpRect.Y += (scaleTextSizeX.Height);
                tmpRect.Height -= (scaleTextSizeX.Height);
            }

            if ((scalePos & (int)Position.Bottom) != 0)
            {
                tmpRect.Height -= (scaleTextSizeX.Height);
            }
            return tmpRect;
        }

        public void SetGraphics(Graphics g)
        {
            this.gs = g;
        }



        public Rect Show()
        {
            return Show(gs, myRect);
        }

        public Rect Show(Graphics g, Rect r)
        {
            myRect = r;
            gs = g;

            //    g.Clear(backGround);

            windowRect = GetRemainRect();



            Rectangle border = new Rectangle((int)windowRect.TopLeft.X, (int)windowRect.TopLeft.Y, (int)windowRect.Width, (int)windowRect.Height);

            //   g.FillRectangle(new SolidBrush(Color.Yellow), new RectangleF((float)windowRect.TopLeft.X, (float)windowRect.TopLeft.Y, (float)windowRect.Width, (float)windowRect.Height));
            g.DrawRectangle(borderPen, border);

            DrawScaleX(g, windowRect, windowPadding.top, windowPadding.bottom);
            DrawScaleY(g, windowRect, windowPadding.left, windowPadding.right);

            DrawReferenceLines(g);

            return windowRect;
        }

        public bool IsInWindowRect(PixelPoint p)
        {
            if (p.X < windowRect.Left || p.Y < windowRect.Top || p.X > windowRect.Right || p.Y > windowRect.Bottom)
            {
                return false;
            }

            return true;
        }

        private void DrawReferenceLines(Graphics g)
        {
            foreach (var line in referenceLines)
            {
                if (line.value < dataWnd.valueRangeY.minValue || line.value > dataWnd.valueRangeY.maxValue)
                {
                    continue;
                }

                ValuePoint valuePoint1 = new ValuePoint(this.dataWnd.valueRangeX.minValue, line.value);
                ValuePoint valuePoint2 = new ValuePoint(this.dataWnd.valueRangeX.maxValue, line.value);

                PixelPoint p1 = this.Point2Pixel(valuePoint1);
                PixelPoint p2 = this.Point2Pixel(valuePoint2);

                Pen scalePen = null;
                scalePen = new Pen(line.color, 1);
                if (line.type == LineType.Dot)
                {
                    scalePen.DashPattern = new float[] { 1f, 1f };
                }
                else if (line.type == LineType.Dashed)
                {
                    scalePen.DashPattern = new float[] { 3f, 2f };
                }



                g.DrawLine(scalePen, p1.X, p1.Y, p2.X, p2.Y);
            }
        }
        private void DrawScaleX(Graphics g, Rect r, int paddingTop, int paddingBottom)
        {
            PointF p1 = new PointF((float)r.TopLeft.X, (float)r.TopLeft.Y);
            PointF p2 = new PointF((float)r.BottomLeft.X, (float)r.BottomLeft.Y);

            double pixelInterval = r.Width / (scaleX.scaleCounts - 1);
            double valueInterval = (dataWnd.valueRangeX.maxValue - dataWnd.valueRangeX.minValue) / (scaleX.scaleCounts - 1);
            for (int i = 0; i < scaleX.scaleCounts; i++)
            {
                //刻度值
                double minScaleValue = dataWnd.valueRangeX.minValue; //初始值，最左边的刻度
                double scaleValue = minScaleValue + i * valueInterval;
                string fmt = string.Format("{{{0}}}", scaleX.scaleTextFormat);
                string scaleStr = string.Format(fmt, scaleValue);
                //string scaleStr = scaleValue.ToString("f2");

                SizeF textSize = gs.MeasureString(scaleStr, scaleX.scaleTextFont);

                if ((scalePos & (int)Position.Top) != 0) //first
                {
                    if (i == 0)
                    {
                        g.DrawString(scaleStr, scaleX.scaleTextFont, scaleX.scaleTextBrush, new PointF(p1.X, p1.Y - textSize.Height - paddingTop));
                    }
                    else if (i == scaleX.scaleCounts - 1)//last
                    {
                        g.DrawString(scaleStr, scaleX.scaleTextFont, scaleX.scaleTextBrush, new PointF(p1.X - textSize.Width, p1.Y - textSize.Height - paddingTop));
                    }
                    else //others
                    {
                        g.DrawString(scaleStr, scaleX.scaleTextFont, scaleX.scaleTextBrush, new PointF(p1.X - textSize.Width / 2, p1.Y - textSize.Height - paddingTop));
                    }

                }

                if ((scalePos & (int)Position.Bottom) != 0)
                {
                    if (i == 0)
                    {
                        g.DrawString(scaleStr, scaleX.scaleTextFont, scaleX.scaleTextBrush, new PointF(p2.X, p2.Y + paddingBottom));
                    }
                    else if (i == scaleX.scaleCounts - 1)//last
                    {
                        g.DrawString(scaleStr, scaleX.scaleTextFont, scaleX.scaleTextBrush, new PointF(p2.X - textSize.Width, p2.Y + paddingBottom));
                    }
                    else //others
                    {
                        g.DrawString(scaleStr, scaleX.scaleTextFont, scaleX.scaleTextBrush, new PointF(p2.X - textSize.Width / 2, p2.Y + paddingBottom));
                    }
                }


                //刻度线
                if (i > 0 && i < (scaleX.scaleCounts - 1))//起始刻度不需要显示，已经显示border了
                {
                    Pen scalePen = null;
                    scalePen = new Pen(scaleX.lineProperty.color, scaleX.lineProperty.width);
                    if (scaleX.lineProperty.type == LineType.Dot)
                    {
                        scalePen.DashPattern = new float[] { 1f, 1f };
                    }
                    else if (scaleX.lineProperty.type == LineType.Dashed)
                    {
                        scalePen.DashPattern = new float[] { 3f, 2f };
                    }
                    else if (scaleX.lineProperty.type == LineType.LongDashed)
                    {
                        scalePen.DashPattern = new float[] { 3f, 6f };
                    }
                    else if (scaleX.lineProperty.type == LineType.LongDot)
                    {
                        scalePen.DashPattern = new float[] { 1f, 5f };
                    }

                    g.DrawLine(scalePen, p1, p2);
                }

                p1.X += (float)pixelInterval;
                p2.X += (float)pixelInterval;
            }

        }

        private void DrawScaleY(Graphics g, Rect r, int paddingLeft, int paddingRight)
        {

            PointF p1 = new PointF((float)r.TopLeft.X, (float)r.TopLeft.Y);
            PointF p2 = new PointF((float)r.TopRight.X, (float)r.TopRight.Y);

            double pixelInterval = r.Height / (scaleY.scaleCounts - 1);
            double valueInterval = (dataWnd.valueRangeY.maxValue - dataWnd.valueRangeY.minValue) / (scaleY.scaleCounts - 1);

            for (int i = 0; i < scaleY.scaleCounts; i++)
            {
                //刻度值
                double maxScaleValue = dataWnd.valueRangeY.maxValue; //初始值，最上面的刻度
                double scaleValue = maxScaleValue - i * valueInterval;
                string fmt = string.Format("{{{0}}}", scaleY.scaleTextFormat);
                string scaleStr = string.Format(fmt, scaleValue);
                //string scaleStr = scaleValue.ToString("f2");
                SizeF textSize = gs.MeasureString(scaleStr, scaleY.scaleTextFont);

                if ((scalePos & (int)Position.Left) != 0)
                {
                    //if (i == 0) //first
                    //{
                    //    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p1.X - textSize.Width - paddingLeft, p1.Y));
                    //}
                    //else if (i == scaleY.scaleCounts - 1) //last
                    //{
                    //    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p1.X - textSize.Width - paddingLeft, p1.Y - textSize.Height));
                    //}
                    //else  //others
                    //{
                    //    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p1.X - textSize.Width - paddingLeft, p1.Y - textSize.Height / 2));
                    //}
                    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p1.X - textSize.Width - paddingLeft, p1.Y - textSize.Height / 2));
                }

                if ((scalePos & (int)Position.Right) != 0)
                {
                    //if (i == 0) //first
                    //{
                    //    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p2.X + paddingRight, p2.Y));
                    //}
                    //else if (i == scaleY.scaleCounts - 1) //last
                    //{
                    //    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p2.X + paddingRight, p2.Y - textSize.Height));
                    //}
                    //else  //others
                    //{
                    //    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p2.X + paddingRight, p2.Y - textSize.Height / 2));
                    //}

                    g.DrawString(scaleStr, scaleY.scaleTextFont, scaleY.scaleTextBrush, new PointF(p2.X + paddingRight, p2.Y - textSize.Height / 2));
                }

                //刻度线
                if (i > 0 && i < (scaleY.scaleCounts - 1))//起始刻度不需要显示，已经显示border了
                {
                    Pen scalePen = null;
                    scalePen = new Pen(scaleY.lineProperty.color, scaleY.lineProperty.width);
                    if (scaleY.lineProperty.type == LineType.Dot)
                    {
                        scalePen.DashPattern = new float[] { 1f, 1f };
                    }
                    else if (scaleY.lineProperty.type == LineType.Dashed)
                    {
                        scalePen.DashPattern = new float[] { 3f, 2f };
                    }
                    else if (scaleY.lineProperty.type == LineType.LongDashed)
                    {
                        scalePen.DashPattern = new float[] { 3f, 6f };
                    }
                    else if (scaleY.lineProperty.type == LineType.LongDot)
                    {
                        scalePen.DashPattern = new float[] { 1f, 5f };
                    }

                    g.DrawLine(scalePen, p1, p2);
                }

                p1.Y += (float)pixelInterval;
                p2.Y += (float)pixelInterval;
            }
        }

        public void UpdateScaleValue()
        {
            UpdateScaleValueX();

            UpdateScaleValueY();
        }

        public void UpdateScaleValueX()
        {
            if (scaleX.mode == SCALE_SHOW_MODE.Readable)
            {
                CalcValueLimited(scaleX.valueRange.minValue, scaleX.valueRange.maxValue, scaleX.scaleCounts - 1, ref dataWnd.valueRangeX);
            }
            else
            {
                dataWnd.valueRangeX.minValue = scaleX.valueRange.minValue;
                dataWnd.valueRangeX.maxValue = scaleX.valueRange.maxValue;
            }
        }

        public void UpdateScaleValueY()
        {
            if (scaleY.mode == SCALE_SHOW_MODE.Readable)
            {
                CalcValueLimited(scaleY.valueRange.minValue, scaleY.valueRange.maxValue, scaleY.scaleCounts - 1, ref dataWnd.valueRangeY);
            }
            else
            {
                dataWnd.valueRangeY.minValue = scaleY.valueRange.minValue;
                dataWnd.valueRangeY.maxValue = scaleY.valueRange.maxValue;
            }
        }

        public void CalcValueLimited(double minValue, double maxValue, int splitterNumber, ref ValueRange valueRange)
        {
            double tempMinValue = minValue;
            double tempMaxValue = maxValue;

            int[] magic = { 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 500, 1000, 5000, 10000, 50000, 100000 };//魔数数组经过扩充，放宽魔数限制避免出现取不到魔数的情况。

            double tempGap = (tempMaxValue - tempMinValue) / splitterNumber;
            double multiple = Math.Floor(Math.Log10(tempGap) - 1);
            multiple = Math.Pow(10, multiple);
            double tempStep = tempGap / multiple;
            double estep = -1;

            for (int i = 0; i < magic.Length; i++)
            {
                if (magic[i] > tempStep)
                {
                    estep = magic[i] * multiple;
                    break;
                }
            }
            if (estep > 0)
            {
                //求出期望的最大刻度和最小刻度，为estep的整数倍
                valueRange.maxValue = (int)(tempMaxValue / estep + 1) * estep;
                valueRange.minValue = (int)(tempMinValue / estep - 1) * estep;
            }
            else
            {
                valueRange.maxValue = tempMaxValue;
                valueRange.minValue = tempMinValue;
            }

            if (tempMaxValue == 0) valueRange.maxValue = 0;
            if (tempMinValue == 0) valueRange.minValue = 0;
        }
    }
}
